package packing;
import java.io.FileWriter;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.Arrays;

/*
 * Java implementation of the Bischoff and Ratcliff dataset generator, Described in:
 * 
 * "Issues in the Development of Approaches to Container Loading"
 * Bischoff, E. E.; Ratcliff, M. S. W.
 * Omega, 23, pp 377-390, 1995. 
 * 
 * Matthew Hyde
 * ASAP Research Group
 * School of Computer Science
 * University of Nottingham
 * Jubilee Campus
 * Wollaton Road
 * Nottingham, NG8 1BB
 * UK
 * web: www.cs.nott.ac.uk/~mvh
 * 
 * The following link leads to a C++ implementation of the same dataset generator, 
 * implemented by Sam Allen, also of the ASAP Research Group.
 * This Java implementation was created by referring to his C++ implementation
 * www.cs.nott.ac.uk/~sda/research.shtml
 * 
 */

public class BRGen {

	//modify these to get the different files
	//for reference:
	//file - numberofboxes 
	//BR1 - 3 : BR2 - 5 : BR3 - 8 : BR4 - 10 : BR5 - 12
	//BR6 - 15 : BR7 - 20 : BR8 - 30 : BR9 - 40 : BR10 - 50
	static int numberofboxes = 3;
	static String file = "br1.txt";
	
	static int numberofinstances = 100;
	
	//constants for the random number generator
	static int mod = 2147483647;
	static int multiplier = 16807;
	static int q = 127773;
	static int r = 2836;

	static int seed;

	//min and max box dimensions
	static int[] a = {30, 25, 20};
	static int[] b = {120, 100, 80};

	static int L = 2;//stability constraint
	static int T = 587*233*220;//target total volume for the boxes

	/*
	 * the method getNextRandom is taken from Park and Miller (1988)
	 * random number generators: good ones are hard to find.
	 * Commun. ACM. 31, 1192-1201
	 * (As referenced in Bischoff and Ratcliff (1995))
	 */
	private static double getNextRandom() {
		int hi = seed / q;
		int lo = seed % q;
		int test = multiplier * lo - r * hi;
		if (test > 0) {
			seed = test;
		} else {
			seed = test + mod;
		}
		//System.out.println(seed);
		return (double)seed / (double)mod;
	}

	public static void main(String argv[]) {
		try {
			FileWriter f = new FileWriter(file);
			PrintWriter pr = new PrintWriter(f);
			
			//number of instances printed at the top of the file
			pr.println(numberofinstances);

			for (int set = 1; set <= numberofinstances; set++) {
			
				//set the seed
				seed = 2502505 + 100* (set-1);

				//print the instance headers
				pr.println(set + " " + seed);
				pr.println(587 + " " + 233 + " " + 220);
				pr.println(numberofboxes);

				//ignore the first ten random numbers
				for (int x = 0; x < 10; x++) {
					getNextRandom();
				}

				//the 
				int[][] boxes = new int[numberofboxes][3];
				int[][] verticalorientation = new int[numberofboxes][3];
				int[] boxnumbers = new int[numberofboxes];
				int[] boxvolumes = new int[numberofboxes];

				//create the box types
				for (int p = 0; p < numberofboxes; p++) {

					//set the dimensions of this box type, keeping track of the minimum for later
					double min = Double.MAX_VALUE;
					for (int x = 0; x < 3; x++) {
						boxes[p][x] = a[x] + (int)Math.floor(getNextRandom() * (b[x] - a[x] + 1));
						if (boxes[p][x] < min) {
							min = boxes[p][x];
						}
					}

					//sort the sizes into largest first, this is how the file is formatted
					Arrays.sort(boxes[p]);
					int temp = boxes[p][2];
					boxes[p][2] = boxes[p][0];
					boxes[p][0] = temp;

					//determine if each of the three dimensions can be placed in the vertical direction
					for (int x = 0; x < 3; x++) {
						if (((double)boxes[p][x] / min) < 2) {
							verticalorientation[p][x] = 1;
						} else {
							verticalorientation[p][x] = 0;
						}
					}

					//initialise the number of boxes of this piece type
					boxnumbers[p] = 1;

					//store the volume for later
					boxvolumes[p] = boxes[p][0] * boxes[p][1] * boxes[p][2];

				}//end looping piece types

				//determine the number of boxes of each type
				while (true) {
					//calculate the total volume of the current amount of boxes
					int cargovolume = 0;
					for (int p = 0; p < numberofboxes; p++) {
						cargovolume += boxnumbers[p]* boxvolumes[p];
					}

					//randomly choose a box type
					int boxtypeindicator = (int)Math.floor(getNextRandom() * numberofboxes);

					//if another box of this type will push the total volume over the target volume then stop adding boxes
					if (T < cargovolume + boxvolumes[boxtypeindicator]) {
						break;
					} else {
						//else add a box of this type
						boxnumbers[boxtypeindicator]++;
					}
				}//end determining the number of each box type

				//loop the box types and print their details to the file
				for (int p = 0; p < numberofboxes; p++) {
					pr.println((p+1) + " " + boxes[p][0] + " " + verticalorientation[p][0] + " " + 
							boxes[p][1] + " " + verticalorientation[p][1] + " " + 
							boxes[p][2] + " " + verticalorientation[p][2] + " " + 
							boxnumbers[p]);
				}

			}//end for loop, instances in the file
			
			pr.close();
			f.close();
		} catch (IOException e) {
			System.err.println(e.getMessage());
			System.exit(-1);
		}
	}//end main method
}
